package cn.pugle.base.thread.ticketlock;

import java.util.HashMap;

/**
 * https://stackoverflow.com/questions/17069569/thread-synchronization-based-upon-an-id <br/>
 * Usage:
 * <pre>{@code
 *  Object lock = ticketLock.getLock(idToLock);
 *  try {
 *      synchronized (lock) {
 *          //do something
 *      }
 *  } finally {
 *      ticketLock.removeLock(idToLock);
 *  }
 * }</pre>
 *
 * @author tzp
 * @since 2018/7/9
 */
public class TicketLock2 implements TicketLock {
    private static HashMap<Long, Lock> ticketLockMap = new HashMap<>();

    @Override
    public Object getLock(Long ticketNumber) {
        synchronized (ticketLockMap) {
            Lock ticketLock = ticketLockMap.get(ticketNumber);
            if (ticketLock == null) {
                ticketLock = new Lock();
                ticketLockMap.put(ticketNumber, ticketLock);
            } else {
                ticketLock.inUseCount++;
            }
            return ticketLock;
        }
    }

    @Override
    public void removeLock(Long ticketNumber) {
        synchronized (ticketLockMap) {
            Lock ticketLock = ticketLockMap.get(ticketNumber);
            if (ticketLock != null && --ticketLock.inUseCount == 0) {
                ticketLockMap.remove(ticketNumber);
            }
        }
    }

    class Lock {
        int inUseCount = 1;
    }
}
